﻿using System;
using System.Globalization;
using System.ServiceModel;
using Cluster;
using Util;

namespace ClusterTest
{
    public class TestClusterManager : ClusterManager
    {
        [Serializable]
        private class TestClusterNode : ClusterNode
        {
            public string Uri; // the intra-cluster communcation service uri
        }

        public static TestClusterManager Leader { get; set; }

        private readonly string uri;

        private ServiceHost serviceHost;

        public TestClusterManager(int port) :
            base("__TEST__", port.ToString(CultureInfo.InvariantCulture))
        {
            uri = string.Format("http://localhost:{0}/Services/TestCluster", port);
        }

        public override void Start(string zkConnectionString, TimeSpan? timeout = null)
        {
            var service = new TestClusterService(this);
            serviceHost = new ServiceHost(service, new Uri(uri));
            serviceHost.Open();

            base.Start(zkConnectionString, timeout);
        }

        public override void Stop()
        {
            base.Stop();

            serviceHost.Abort();
        }

        protected override ClusterNode CreateClsuterNode()
        {
            return new TestClusterNode
            {
                Uri = uri,
            };
        }

        protected override void RequestReplicationFromRemoteNode(string name, ClusterNode node)
        {
            using (var connection = new SoapConnection<ITestClusterService>(((TestClusterNode) node).Uri))
            {
                connection.Channel.Replicate(name);
            }
        }

        protected override void RequestDiscardReplicationFromRemoteNode(string name, ClusterNode node)
        {
            using (var connection = new SoapConnection<ITestClusterService>(((TestClusterNode)node).Uri))
            {
                connection.Channel.DiscardReplication(name);
            }
        }

        protected override void TakeLeadership()
        {
            Leader = this;
        }

        public int NodesInSystem
        {
            get { return ClusterView.Count; }
        }

        public string MyNodeName
        {
            get { return SelfNode.ZkPath; }
        }

        public int ReplicasNumber
        {
            get { return SelfNode.ReplicasNumber; }
        }

        public string MyReplicatorName
        {
            get
            {
                lock (ReplicationView)
                {
                    return ReplicatingNodeName;
                }
            }
        }

        public bool DiscardWasCalled { get; set; }
    }
}
